/*
*  twnauth.c Authenticate with MSN login server using TWN
*  Copyright (c) 2005 Derek Ingrouville (dergro@users.sourceforge.net)
*
*  This program is free software; you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation; either version 2 of the License, or
*  (at your option) any later version.
*
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU Library General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with this program; if not, write to the Free Software
*  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/

#include <string.h>

#include "twnauth.h"
#include "ssl.h"
#include "utility.h"

char *
get_login_server_from_nexus (void)
{
	SSLSocket *sslsock = NULL;
	char *response = NULL;        /* Response to the get request */
	char *dalogin_start = NULL;   /* location of the start of the dalogin field */
	char *dalogin_end = NULL;     /* location of the end of the dalogin field   */
	char *login_server = NULL;    /* URL of the login server */
	int dalogin_len = 0;

	char *nexus = "nexus.passport.com";
	char *get = "GET /rdr/pprdr.asp HTTP/1.0\n\n";

	/* Connect to the passport nexus */
	sslsock = ssl_connect (nexus, 443);
	if (sslsock == NULL)
		return NULL;

	/* Send the get string */
	if (ssl_write (sslsock, get, strlen (get)) < 0)
		return NULL;

	/* Wait for data */
	while (!ssl_data_available (sslsock))
		vobri_sleep (10);

	response = ssl_recv_all (sslsock);
	ssl_close (sslsock);

	if (response == NULL)
		return NULL;

	/* Find the location of the DALogin field in the reveived data */
	dalogin_start = g_strrstr (response, "DALogin=");
	if (dalogin_start == NULL)
		return NULL;

	dalogin_start += strlen ("DALogin=");

	/* Find the location of the ',' terminating this field */
	dalogin_end = g_strstr_len (dalogin_start, strlen (dalogin_start), ",");
	if (dalogin_end == NULL)
		return NULL;

	/* Get length of the value of the DALogin field */
	dalogin_len = (dalogin_end - dalogin_start);
	g_return_val_if_fail (dalogin_len > 0, NULL);

	login_server = (char *) g_malloc (dalogin_len + 1);
	if (login_server != NULL)
		g_strlcpy (login_server, dalogin_start, dalogin_len + 1);

	return login_server;
}

static char *
get_request_str (MsnSession *session, const char *server, const char *page, const char *challenge)
{
	char *passport = NULL;             /* urlencoded passport  */
	char *password = NULL;             /* urlencoded password  */

	/* strings that will be sent to the login server */
	char *get = NULL;
	char *passver = "Authorization: Passport1.4";
	char *org = "OrgVerb=GET,OrgURL=http%3A%2F%2Fmessenger%2Emsn%2Ecom,sign-in=";
	char *host = NULL;
	char *user_agent = "User-Agent: MSMSGS\r\n";
	char *keepalive = "Connection: Keep-Alive\r\n";
	char *cache = "Cache-Control: no-cache\r\n";
		
	char *auth = NULL;
	char *final = NULL;

	g_return_val_if_fail (session != NULL, NULL);
	g_return_val_if_fail (session->acct->passport != NULL, NULL);
	g_return_val_if_fail (session->acct->password != NULL, NULL);
	g_return_val_if_fail (server != NULL, NULL);
	g_return_val_if_fail (page != NULL, NULL);
	g_return_val_if_fail (challenge != NULL, NULL);

	passport = url_encode (session->acct->passport);
	password = url_encode (session->acct->password);

	get = g_strdup_printf ("GET /%s HTTP/1.1\r\n", page);
	auth = g_strdup_printf ("%s %s%s,pwd=%s,%s\r\n",
				passver,
				org,
				passport, 
				password, 
				challenge);

	host = g_strdup_printf ("Host: %s\r\n", server);
	final = g_strconcat (get, auth, user_agent, host, keepalive, cache, "\r\n", NULL);

	g_free (passport);
	g_free (password);
	g_free (get);
	g_free (auth);
	g_free (host);

	return final;
}

static char *
msn_twn_parse_data (const char *buffer)
{

	char *ticket_start = NULL;         /* Location of the start of the ticket */
	char *ticket_end = NULL;           /* Location of the end of the ticket   */
	char *ticket = NULL;               /* authentication ticket */
	int  ticket_len = 0;               /* length of the ticket */

	g_return_val_if_fail (buffer != NULL, NULL);

	g_print ("<<< {%s}****\n\n\n\n", buffer);

	/* Check response */
	if (strstr (buffer, "HTTP/1.1 303 Found")) {
		/* TODO: DO something based on redirect */
		return NULL;
	}
	else if (strstr (buffer, "HTTP/1.1 401 Unauthorized"))
	{
		/* TODO: Wrong Username / Password */
		return NULL;
	}
	else if (!strstr (buffer, "HTTP/1.1 200 OK"))
	{
		/* TODO: Unkown Response */
		return NULL;
	}

	ticket_start = g_strstr_len (buffer, strlen (buffer), "from-PP='");
	g_return_val_if_fail (ticket_start != NULL, NULL);
	
	ticket_start += strlen ("from-PP='");

	ticket_end = strstr (ticket_start, "',") + 1;
	g_return_val_if_fail (ticket_end != NULL, NULL);

	g_assert (ticket_end > ticket_start);
	ticket_len = (unsigned int) (ticket_end - ticket_start);
	ticket = g_new (char, ticket_len);

	if (ticket != NULL)
		g_strlcpy (ticket, ticket_start, ticket_len);

	g_print ("TICKET = %s\n", ticket);

	return ticket;
}

char *
msn_get_twn_ticket (MsnSession *session, const char *login_server, const char *challenge)
{
	SSLSocket *sslsock = NULL;
	char *server = NULL;               /* Login server */
	char *page = NULL;	           /* Page to request */
	char **split_url =  NULL;          /* Buffer to hold split up url string */

	char *request = NULL;              /* String to send to server */
	char *receive_buf = NULL;          /* Hold received data */
	char *ticket = NULL;

	g_return_val_if_fail (session != NULL, NULL);
	g_return_val_if_fail (session->notif->connected, NULL);
	g_return_val_if_fail (login_server != NULL, NULL);
	g_return_val_if_fail (challenge != NULL, NULL);

	/* Get server and page */
	split_url = g_strsplit (login_server, "/", 2);

	if (split_url[0] != NULL && split_url[1] != NULL) {
		server = g_strdup (split_url[0]);
		page = g_strdup (split_url[1]);
	} else {
		g_strfreev (split_url);
		return NULL;
	}
	g_strfreev (split_url);

	sslsock = ssl_connect (server, 443);
	if (sslsock == NULL) {
		g_free (server);
		g_free (page);
		return NULL;
	}

	request = get_request_str (session, server, page, challenge);
	g_free (server);
	g_free (page);
	g_return_val_if_fail (request != NULL, NULL);

	g_print ("<<< {%s}****\n\n\n\n", request);
	ssl_write (sslsock, request, strlen (request));

	/* TODO: sleeping needed? */
	/* Wait for data */
	while (!ssl_data_available (sslsock))
		vobri_sleep (10);

	receive_buf = ssl_recv_all (sslsock);

	ticket = msn_twn_parse_data (receive_buf);

	g_free (request);
	g_free (receive_buf);
	ssl_close (sslsock);

	return ticket;
}
